--[[	$Id: gotMacros.lua 3105 2013-04-19 05:46:19Z sdkyron@gmail.com $	]]

local _, gotMacros = ...;

gotMacros.eventFrame = CreateFrame("Frame", nil, UIParent);

LoadAddOn("Blizzard_MacroUI");
local macros = gM_Macros;

local buttons = {};
local prefix = "gotMacros_";

local QUESTION_MARK_ICON = "INV_MISC_QUESTIONMARK";

local function NoSoundPreClick()
	SetCVar("Sound_EnableSFX", 0);
end

local function NoSoundPostClick()
	SetCVar("Sound_EnableSFX", 1);
end

local function LevelConditional(wholeMatch)
	local levelComparison, positiveCase, negativeCase = wholeMatch:match("lvl{(.-)?(.-):(.+)}");
	if (loadstring("return " .. UnitLevel("player") .. levelComparison)()) then
		return positiveCase;
	else
		return negativeCase;
	end
end

local function ParseEscapeSequences(text)
	text = text:gsub("(lvl%b{})", LevelConditional);
	text = text:gsub("sid{(%d+)}", GetSpellInfo);
	text = text:gsub("iid{(%d+)}", GetItemInfo);
	return text;
end

local function SetUpMacro(name, body, nosound)
	local btn = buttons[name];
	if not btn then
		btn = CreateFrame("Button", prefix..name, UIParent, "SecureUnitButtonTemplate");
		buttons[name] = btn;
	end

	if nosound then
		btn:SetScript("PreClick", NoSoundPreClick);
		btn:SetScript("PostClick", NoSoundPostClick);
	end

	if body:len() > 1023 then
		print("Gotai is lazy, no macros longer than 1023 chars plx!");
	end

	btn:SetAttribute("type", "macro");
	btn:SetAttribute("macrotext", body);
end

local function CreateBlizzardMacro(name, perChar, icon)
	if not buttons[name] then
		return print(string.format("No button called %q could be found.", tostring(name)));
	end

	if icon then
		icon = icon:match("Interface.Icons.(.+)") or icon;
	end

	local macroname = "gM_"..name:sub(1,13);
	local macrobody = string.format("/click %s", buttons[name]:GetName());
	local show = macros[name].show;
	if show then
		show = string.format("#showtooltip %s\n", ParseEscapeSequences(show));
		if show:len() + macrobody:len() <= 255 then
			macrobody = show..macrobody;
		end
	end

	local index = GetMacroIndexByName(macroname)
	if index > 0 then
		EditMacro(index, nil, icon or QUESTION_MARK_ICON, macrobody);
	else
		local Macros, PerCharMacros = GetNumMacros()
		if perChar and PerCharMacros >= MAX_CHARACTER_MACROS then
			perChar = nil;
		end
		if not perChar and Macros >= MAX_ACCOUNT_MACROS then
			return print("Your macro slots are all full, please delete some macros and reload.");
		end
		CreateMacro(macroname, icon or QUESTION_MARK_ICON, macrobody, perChar);
	end
end

local function ValidForSpec(macroTable, spec)
	if (not spec) then
		spec = GetSpecialization();
	end

	if not macroTable.spec or (spec and macroTable.spec:find(spec)) then
		return true;
	end
end

local function ValidForClass(macroTable, class)
	if (not class) then
		class = caelLib.playerClass;
	end

	if (not macroTable.class or macroTable.class == class) then
		return true;
	end
end

function CreateMacros()
	local NumMacros, NumMacrosPerChar = GetNumMacros();
	local playerClass = caelLib.playerClass;
	local currentSpec = GetSpecialization();

	for i = NumMacros, 1, -1 do
		local name = GetMacroInfo(i):match("^gM_(.+)");
		if name and (not macros[name] or not macros[name].blizzmacro or not ValidForClass(macros[name], playerClass) or not ValidForSpec(macros[name], currentSpec)) then
			DeleteMacro(i);
		end
	end

	for i = 37 + (NumMacrosPerChar - 1 or 0), 37, -1 do
		local name = GetMacroInfo(i):match("^gM_(.+)");
		if name and (not macros[name] or not macros[name].blizzmacro or not ValidForClass(macros[name], playerClass) or not ValidForSpec(macros[name], currentSpec)) then
			DeleteMacro(i);
		end
	end

	for k,v in pairs(macros) do
		if (not v.char or v.char:find(caelLib.playerName)) and ValidForClass(v, playerClass) and ValidForSpec(v, currentSpec) then
			SetUpMacro(k, ParseEscapeSequences(v.body:gsub("\n\t*", "\n")), v.nosound);
			if v.blizzmacro then
				CreateBlizzardMacro(k, v.perChar, v.icon);
			end
		end
	end
end

gotMacros.eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
gotMacros.eventFrame:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED");
gotMacros.eventFrame:SetScript("OnEvent", function(self, event, ...)
	if (event ~= "ACTIVE_TALENT_GROUP_CHANGED") then
		self:UnregisterEvent(event);
	end
	
	if InCombatLockdown() then
		return self:RegisterEvent("PLAYER_REGEN_ENABLED")
	end
	
	CreateMacros();
end)
--[[
local _GetActionText = GetActionText
GetActionText = function(action)
   local text = _GetActionText(action)
   if text and text:find("^gM_") then
      return text:sub(4)
   else
      return text
   end
end
--]]